package com.limanyik.family.gateway.filter;

import com.limanyik.family.common.config.RedisConfig;
import com.limanyik.family.common.entity.BasisMenus;
import com.limanyik.family.common.sinterface.entity.WebUserData;
import com.limanyik.family.common.utils.FamilyHttpRequest;
import com.limanyik.family.common.utils.InteriorEncryptUtil;
import com.limanyik.family.common.utils.UserUtil;
import com.limanyik.family.gateway.config.UserMenusConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 权限过滤
 */
public class PermissionFilter implements GlobalFilter, GatewayFilter, Ordered {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    UserMenusConfig userMenusConfig;

    /**
     * 根据缓存获取用户信息判断是否具备访问权限
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取HTTP请求信息 permissionFilter
        ServerHttpRequest serverHttpRequest = exchange.getRequest();
        // 请求方式(POST/GET/DELETE/PUT)
        String method = serverHttpRequest.getMethodValue();
        // 请求IP地址
        String requestIp = serverHttpRequest.getRemoteAddress().getHostString();
        // 媒体类型
        MediaType mediaType = serverHttpRequest.getHeaders().getContentType();
        // 请求路径 macro Record Implement
        URI url = serverHttpRequest.getURI();
        String path = url.getPath();
        // 请求头部信息
        HttpHeaders httpHeaders = serverHttpRequest.getHeaders();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 如果是开发路径则直接放行
        if (userMenusConfig.isOpenUrl(path)) {
            return chain.filter(exchange);
        }

        FamilyHttpRequest familyHttpRequest = (FamilyHttpRequest) exchange.getAttributes().get("familyHttpRequest");
        long timestamp = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        long requestTime = familyHttpRequest.getRequestTimeSpear();
        // 判断是否超时，判断5分钟超市
        if (timestamp - requestTime > 30000 || requestTime - timestamp < -30000) {
            return Mono.error(new Exception("请求超时"));
        }
        // 校验签名
        String verifySign = InteriorEncryptUtil.encrypt(familyHttpRequest.getToken() + familyHttpRequest.getRequestTimeSpear(), InteriorEncryptUtil.MD5);
        if (!familyHttpRequest.getSign().equals(verifySign)) {
            // return Mono.error(new Exception("签名不匹配"));
        }

        // 校验访问路径权限
        WebUserData webUserData = UserUtil.getWebUserCacheByToken(familyHttpRequest.getToken());
        if (null == webUserData) {
            return Mono.error(new Exception("token已过期"));
        }
        List<BasisMenus> menus = webUserData.getMenus().stream().filter(basisMenus -> basisMenus.getUrl().equals(path)).collect(Collectors.toList());
        if (menus.size() <= 0) {
            return Mono.error(new Exception("无权访问"));
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -30;
    }
}
